package com.card.game.ddz;

import java.util.Vector;

import com.card.game.Card;
import com.card.game.QzUtils;

public class DdzHand {
	// 花色 (-1=解析的时候出现错误,0=黑桃,1=红桃,2=梅花,3=方片,4=王)
	// 序号 (小王的序号0,大王的序号是1,其他标准的牌:2--13对应牌面的牌,14对应"A"牌(因为"A"牌比K牌还大),15对应2, -1:获取错误)
	public Vector<Card> cards;// 牌列表向量
	public Vector<Card> allCards;// 所有剩下的牌向量
	public int value;// 标识值
	public Card bigcard = null;// 最大的牌对象
	public Card smallCard = null; // 一手牌中最小的牌

	// 一般牌型:
	public static final int SINGLE = 0; // 单牌:单个牌。例如: '8'或者'4'
	public static final int PAIR = 1; // 对牌:两个点数相同的牌。 例如"55"或者'88'
	public static final int THREE = 2; // 三张牌:三张点数相同的牌。例如"555"或者'888'
	public static final int THREESINGLE = 3; // 三带一:三张同点牌 ＋ 一张单牌。例如:三张３＋单４,例如'3334'
	public static final int THREEPAIR = 4; // 三带二:三张同点牌 ＋ 一对牌。例如:三张３＋对４,例如'33344'
	public static final int LINK = 5; // 单顺:五张或更多连续的单牌。例如:单３＋单４＋单５＋单６＋单７。不包括２点和双王。,例如'345678910JQKA'
	public static final int LINKPAIR = 6; // 双顺:三对或更多连续的对牌。例如:对３＋对４＋对５。不包括２点和双王。例如''334455667788991010JJQQKKAA'
	public static final int LINKTHREE = 7; // 三顺:二个或更多连续的三张牌。例如:三张３＋三张４＋三张５。不包括２点和双王。也叫飞机不带翅膀。例如'333444555'
	public static final int LINKTHREE_CB = 8; // 飞机带翅膀。三顺＋同数量的单牌（或同数量的对牌）。例如:三张３＋三张４＋对５＋对６ 或 三张３＋三张４＋三张５＋单６＋单７＋单８
	public static final int FOUR_TWOSINGLE = 9; // 四带二单牌:四张牌＋任意两张单牌例如:四张５＋单３＋单８
	public static final int FOUR_TWOPAIR = 10; // 四带二对牌:四张牌＋任意两对牌 例如四张４＋对５＋对７
	// 特别牌型:
	public static final int NONE = -1; // -----是不符合游戏规则的牌列表
	public static final int PASS = 100; // pass
	public static final int BOMB = 200; // 炸弹:四张同点牌。如四个3。除火箭和比自己大的炸弹外,什么牌型都可打。
	public static final int HUOJIAN = 400; // 火箭:即双王（双王牌）,什么牌型都可打,是最大的牌。
	public static final int RUAN_BOMB = 150; // 软炸弹--癞子炸弹

	/**
	 * 构造函数
	 * 
	 * @param vector
	 *            牌列表
	 * @param isStringName
	 *            是否列表中的牌时字符串形式存放的
	 */
	public DdzHand(Vector<Card> vector, Vector<Card> allCard) {
		if (vector == null || vector.isEmpty()) {
			this.value = PASS;
			return;
		}
		Vector<Card> clones = (Vector<Card>) vector.clone();
		this.cards = vector;
		this.allCards = allCard;
		analyze();// 进行分析!!!!!!!!!!!!!!
		this.cards = clones;
	}

	/**
	 * 取出列表中牌的个数
	 * 
	 * @return
	 */
	public int size() {
		return cards.size();
	}

	/**
	 * 是规则牌吗
	 * 
	 * @return
	 */
	public boolean isRegular() {
		return value >= 0; // 备注:0代表单,也是允许的
	}

	/**
	 * 检查是否是"火箭"
	 * 
	 * @return
	 */
	public boolean isHhuoJian() {
		if (cards.size() != 2)
			return false;// 如果不是2张牌则认为不是火箭
		return cards.get(0).isJoker() && cards.get(1).isJoker();// 要求两张牌斗是王
	}

	/**
	 * 检查是否是"对"
	 * 
	 * @param vector
	 *            牌列表
	 * @param i
	 *            从第几个元素开始比较
	 * @return
	 */
	public boolean isPair(Vector<Card> vector, int i) {
		if (vector == null || vector.size() < i + 2)
			return false; // 范围检查,防止越界

		Card card = vector.get(0 + i);
		Card card1 = vector.get(1 + i);

		return card.getIndex() == card1.getIndex(); // 比较从指定位置开始两张牌的序号是否一样
	}

	/**
	 * 检查是否是三张牌:三张点数相同的牌。例如"555"或者'888'
	 * 
	 * @param vector
	 *            牌列表
	 * @param i
	 *            从第几个元素开始比较
	 * @return
	 */
	public boolean isThree(Vector<Card> vector, int i) {
		if (vector == null || vector.size() < i + 3)
			return false;// 范围检查,防止越界

		Card card = vector.get(0 + i);
		Card card1 = vector.get(1 + i);
		Card card2 = vector.get(2 + i);
		if (card.getIndex() == card1.getIndex() && card.getIndex() == card2.getIndex()) // 比较序号是否一样
		{
			bigcard = card2; // 如果一样,则设置bigcard,因为根据游戏规则,如果有3同张,则比较3同张的大小
			return true;
		} else {
			return false;
		}
	}

	/**
	 * 检查是否是三带一:三张同点牌 ＋ 一张单牌。例如:三张３＋单４,例如'3334' +不能带2和王
	 * 
	 * @param vector
	 * @return
	 */
	boolean isThreeSingle() {
		if (cards == null || cards.size() != 4)
			return false;// 范围检查
		return (isThree(cards, 0) && cards.get(3).isNo2Joker()) || (isThree(cards, 1) && cards.get(0).isNo2Joker());
	}

	/**
	 * 检查是否是连,五张或更多连续的单牌。例如:单３＋单４＋单５＋单６＋单７。不包括２点和双王。,例如'345678910JQKA'
	 */
	boolean isLink() {
		if (cards == null || cards.size() < 5)
			return false;// 范围检查,保证联的个数不小于最少允许的牌的个数,重要!

		for (int i = 0; i < cards.size() - 1; i++) {
			Card card = cards.get(i);
			Card card1 = cards.get(i + 1);

			if (card.getIndex() == 15 || card1.getIndex() == 15)
				return false;// 不允许包含2
			if (card.isJoker() || card1.isJoker())
				return false;// 不允许包含王

			if (card1.getIndex() != card.getIndex() + 1)
				return false;
		}

		bigcard = cards.lastElement(); // 如果是联则更新bigcard
		smallCard = cards.firstElement();
		return true;
	}

	/**
	 * 检查是否是三带二:三张同点牌 ＋ 一对牌。例如:三张３＋对４,例如'33344'
	 * 
	 * @param vector
	 * @return
	 */
	public boolean isThreePair() {
		if (cards == null || cards.size() != 5)
			return false;// 范围检查

		if (isPair(cards, 0) && isThree(cards, 2))
			return true;
		if (isThree(cards, 0) && isPair(cards, 3))
			return true;
		return false;
	}

	/**
	 * 检查是否是双顺:三对或更多连续的对牌。例如:对３＋对４＋对５。不包括２点和双王。例如''334455667788991010JJQQKKAA'
	 * 
	 * @param vector
	 * @return
	 */
	boolean isLinkPair() {
		if (cards == null || cards.size() < 6 || cards.size() % 2 != 0)
			return false;// 要求必须是偶数张牌!并且不小于6张牌(备注:可以是6张)

		for (int i = 0; i < cards.size(); i += 2)
			if (!isPair(cards, i))
				return false; // 依次检查是否是对

		// 是否是简单连（注意是要间隔一个比较）
		for (int i1 = 0; i1 < cards.size() - 2; i1 += 2) {
			Card card = cards.get(i1);
			Card card1 = cards.get(i1 + 2);

			if (card.getIndex() == 15 || card1.getIndex() == 15)
				return false;// 不允许包含2
			if (card.isJoker() || card1.isJoker())
				return false;// 不允许包含王

			if (card1.getIndex() != card.getIndex() + 1)
				return false;
		}

		bigcard = cards.lastElement(); // 如果是联则更新bigcard
		smallCard = cards.firstElement();
		return true;
	}

	/**
	 * 检查是否是三顺:二个或更多连续的三张牌。例如:三张３＋三张４＋三张５。不包括２点和双王。也叫飞机不带翅膀。例如'333444555'
	 * 
	 * @param vector
	 * @return
	 */
	boolean isLinkThree(Vector<Card> aVec) {
		if (aVec == null || aVec.size() < 6 || aVec.size() % 3 != 0)
			return false;// 范围检查,要求必须是3的倍数张牌!并且不小于6张牌(备注:可以是6张)

		for (int i = 0; i < aVec.size(); i += 3)
			if (!isThree(aVec, i))
				return false; // 依次检查是否是3同张

		// 是否是简单连（注意是要间隔2个比较）
		for (int i1 = 0; i1 < aVec.size() - 3; i1 += 3) {
			Card card = aVec.get(i1);
			Card card1 = aVec.get(i1 + 3);

			if (card.getIndex() == 15 || card1.getIndex() == 15)
				return false;// 不允许包含2
			if (card.isJoker() || card1.isJoker())
				return false;// 不允许包含王

			if (card1.getIndex() != card.getIndex() + 1)
				return false;
		}

		bigcard = aVec.lastElement(); // 如果是联则更新bigcard
		smallCard = aVec.firstElement();
		return true;
	}

	/**
	 * 检查是否是炸弹,四张牌点相同的牌,如:4444
	 * 
	 * @param vector
	 *            牌列表
	 * @param i
	 *            从第几个元素开始比较
	 * @return
	 */
	public boolean isFour(Vector<Card> vector, int i) {
		if (vector == null || vector.size() < i + 4)
			return false;// 范围检查,防止越界

		Card card = vector.get(0 + i);
		Card card1 = vector.get(1 + i);
		Card card2 = vector.get(2 + i);
		Card card3 = vector.get(3 + i);
		if (card.getIndex() == card1.getIndex() && card.getIndex() == card2.getIndex()
				&& card.getIndex() == card3.getIndex()) // 比较序号
		{
			bigcard = card3; // 注意:如果序号一样,则更新最大牌对象（游戏规则）
			return true;
		} else {
			return false;
		}
	}

	/**
	 * 检查是否是四带二单牌:四张牌＋任意两张单牌例如:四张５＋单３＋单８
	 * 
	 * @return
	 */
	boolean isFourTwoSingle() {
		if (cards == null || cards.size() != 6)
			return false;// 范围检查

		return isFour(cards, 0) || isFour(cards, 1) || isFour(cards, 2);
	}

	/**
	 * 检查是否是四带二对牌:四张牌＋任意两对牌 例如四张４＋对５＋对７
	 * 
	 * @return
	 */
	boolean isFourTwoPair() {
		if (cards == null || cards.size() != 8)
			return false;// 范围检查

		if (isPair(cards, 0) && isPair(cards, 2) && isFour(cards, 4))
			return true;
		if (isPair(cards, 0) && isPair(cards, 6) && isFour(cards, 2))
			return true;
		if (isPair(cards, 4) && isPair(cards, 6) && isFour(cards, 0))
			return true;
		return false;
	}

	/**
	 * 检查是否是飞机带翅膀。三顺＋同数量的单牌（或同数量的对牌）。例如:三张３＋三张４＋对５＋对６ 或 三张３＋三张４＋三张５＋单６＋单７＋单８
	 * 
	 * @return
	 */
	boolean isLinkThree_CB() {
		// 把cards复制一份到clonedCards,仅仅对复制品进行操作
		Vector<Card> clonedCards = new Vector<>();
		for (int i = 0; i < cards.size(); i++) {
			clonedCards.add(cards.get(i));
		}

		// 从复制品中挑出3同张到aVec中
		Vector<Card> aVec = new Vector<>();
		for (int i = 0; i < clonedCards.size() - 2; i++) {
			if (this.isThree(clonedCards, i)) {
				aVec.add(clonedCards.get(i));
				aVec.add(clonedCards.get(i + 1));
				aVec.add(clonedCards.get(i + 2));
				i += 2;
			}
		}

		// 把clonedCards中的3同张删除(删除后clonedCards中仅仅剩下单牌或者对牌)
		for (int i = 0; i < aVec.size(); i++) {
			clonedCards.removeElement(aVec.get(i));
		}

		// 检查aVec是三顺,如果不是三顺则直接返回false
		if (!isLinkThree(aVec)) {
			boolean isCan = false;
			// 是一个大飞机 比如 666777888 444 或者 是666777888999 4445 飞机膀子是三张的情况 add by syl
			// 2014-02-08
			if (aVec.size() >= 4) {
				// 先移除前三张
				Vector<Card> cv = new Vector<>();
				Vector<Card> aVecClone = (Vector<Card>) aVec.clone();
				for (int i = 0; i < 3; i++) {
					cv.add(aVecClone.remove(0));
				}
				if (isLinkThree(aVecClone)) {
					aVec.removeAll(cv);
					clonedCards.addAll(cv);
					isCan = true;
				}

				// 移除最后三张
				if (!isCan) {
					cv.clear();
					aVecClone = (Vector) aVec.clone();
					for (int i = 0; i < 3; i++) {
						cv.add(aVecClone.remove(aVecClone.size() - 1));
					}
					if (isLinkThree(aVecClone)) {
						aVec.removeAll(cv);
						clonedCards.addAll(cv);
						isCan = true;
					}
				}

			}
			if (!isCan) {
				return false;
			}
		}

		// 现在aVec中是三顺,计算出三顺的个数
		int iCount = aVec.size() / 3;

		// 检查clonedCards中剩余的牌是否是iCount对
		// if (clonedCards.size() == 2 * iCount) {
		// for (int i = 0; i < clonedCards.size(); i += 2)
		// if (!isPair(clonedCards, i))
		// return false;
		// return true;
		// }

		// 如果不是iCount对,则检查是否是iCount个单牌
		if (clonedCards.size() == iCount) {
			if (clonedCards.size() == 2) {
				if (clonedCards.get(0) != clonedCards.get(1)) {
					return false;
				}
				if (!clonedCards.get(0).isNo2Joker() || !clonedCards.get(1).isNo2Joker()) {
					return false;
				}
			}
			return true;
		} else {
			// 是一个大飞机 是5556667778889994 飞机膀子是三张的情况 add by syl 2014-02-08
			if (isLinkThree(aVec) && iCount == 5 && clonedCards.size() == 1) {
				return true;
			}
			if (isLinkThree(aVec) && iCount == 6 && clonedCards.size() == 2) {
				return true;
			}
		}

		// 以上都不满足,则返回false
		return false;
	}

	/**
	 * -------------------------------------------------------------------------
	 * 分析,要出的[牌
	 * -------------------------------------------------------------------------
	 */
	public void analyze() {
		// 对牌进行排序,确保按牌的大小顺序排列
		sortCards(cards);

		int i = cards.size();// 牌的个数
		// 如果本牌列表中牌的个数小于等于0,则最大牌对象为null,否则为牌列表中最后面的牌
		bigcard = size() <= 0 ? null : cards.lastElement();
		value = -1;// 初始化牌的数值为-1(也就是不符合规则的标志值)

		// 如果牌的个数为0则表示是PASS
		if (i == 0) {
			value = PASS;
			return;
		}

		// 如果是一张则设置成单张的标志
		if (i == 1) {
			if (cards.get(0).isJoker() && allCards.contains(new Card(4, 1)) && allCards.contains(new Card(4, 0))) {

			} else {
				value = SINGLE;
			}
			return;
		}

		// 如果是2张
		if (i == 2) {
			// 先判断是否是火箭,如果是则设置火箭的标志
			if (isHhuoJian()) {
				value = HUOJIAN;
				return;
			}
			// 如果不是火箭则再判断是否是对,如果是对则设置对的标志
			if (isPair(cards, 0))
				value = PAIR;
			return;
		}

		// 如果是3张牌
		if (i == 3) {
			if (isThree(cards, 0))
				value = THREE;// 比较是否是三张牌:三张点数相同的牌。例如"555"或者'888'
			return;
		}

		// 如果是4张牌
		if (i == 4) {
			if (isFour(cards, 0)) {
				// if(LzCardManager.containLzCard(cards) > 0) {
				// value = RUAN_BOMB;
				// }else{
				// }
				value = BOMB; // 如果是炸弹,则设置是炸弹的标志
				return;
			}
			// 当不是炸弹的时候再检查是否是3带1
			if (isThreeSingle())
				value = THREESINGLE; // 比较是否是三带一:三张同点牌 ＋ 一张单牌。例如:三张３＋单４,例如'3334'
			return;
		}

		// 如果是5张牌
		if (i == 5) {
			// 检查是否是连
			if (isLink()) {
				value = LINK;
				return;
			}
			// 如果不是连,则检查是否是三带二
			// if (isThreePair())
			// value = THREEPAIR;
			return;
		}

		// 程序执行到这里的时候牌的张数大于等于6张牌==================================
		// 检查是否是连
		if (isLink()) {
			value = LINK;
			return;
		}
		// 检查是否是双顺:三对或更多连续的对牌。例如:对３＋对４＋对５。不包括２点和双王。例如''334455667788991010JJQQKKAA'
		if (isLinkPair()) {
			value = LINKPAIR;
			return;
		}
		// 检查是否是三顺:二个或更多连续的三张牌。例如:三张３＋三张４＋三张５。不包括２点和双王。也叫飞机不带翅膀。例如'333444555'
		if (isLinkThree(cards)) {
			value = LINKTHREE;
			return;
		}
		// 检查是否是四带二单牌:四张牌＋任意两张单牌例如:四张５＋单３＋单８
		if (isFourTwoSingle()) {
			value = FOUR_TWOSINGLE;
			return;
		}
		// 检查是否是四带二对牌:四张牌＋任意两对牌 例如四张４＋对５＋对７
		// if (isFourTwoPair()) {
		// value = FOUR_TWOPAIR;
		// return;
		// }

		// 检查是否是飞机带翅膀。三顺＋同数量的单牌（或同数量的对牌）。例如:三张３＋三张４＋对５＋对６ 或 三张３＋三张４＋三张５＋单６＋单７＋单８
		if (isLinkThree_CB()) {
			value = LINKTHREE_CB;
			return;
		}

	}

	/**
	 * 比较大小
	 * 
	 * @param hand
	 * @return 如果本牌比目标牌大,则返回值大于0,否则返回值小于等于0(注意:小于0和等于0的含义是一样的,使用的时候没有什么区别!)
	 *         备注:调用本函数的时候,应该调用是后出牌的hand的本函数,参数hand表示比本hand先出的牌
	 */
	public int compareTo(DdzHand hand) {
		// 检查合法性
		if (hand == null || hand.value < 0 || value < 0)
			return 0;

		// 如果本牌列表不是规则的,或者参数牌列表不是规则的,则直接返回0
		if (!isRegular() || !hand.isRegular())
			return 0;

		// 如果本牌列表的分数值跟参数牌列表的分数值不一样
		if (value - hand.value != 0) {
			if (value == HUOJIAN)
				return 1;// 如果我的牌是火箭则我的牌大
			if (hand.value == HUOJIAN)
				return -1;// 如果他的牌是火箭则他的牌大

			// if (value==BOMB) return 1;//如果我的牌是炸弹则我的牌大
			// if (hand.value==BOMB) return -1;//如果他的牌是炸弹则他的牌大
			if (value == BOMB && hand.value < BOMB)
				return 1;// 如果我的牌是炸弹则我的牌大 //bug fix 2005.5.19
			if (hand.value == BOMB && value < BOMB)
				return -1;// 如果他的牌是炸弹则他的牌大

			if (value == RUAN_BOMB && hand.value < RUAN_BOMB)
				return 1;
			if (hand.value == RUAN_BOMB && value < RUAN_BOMB)
				return -1;

			return -1;// 由于我的牌的值不等于他的牌的值,由于我是后出牌的,则我的牌不能出出去
		}

		// 程序执行到这里的时候我的牌值是等于他的牌值的!------------------------------
		if (size() != hand.size())
			return 0;// 如果本牌列表的个数根参数牌列表的个数不一样,则直接返回0,表示本牌列表不大于参数派列表

		// 现在本牌列表的牌的个数等于参数牌列表的牌个数,则分别取出两者各自最大的牌
		Card card = bigCard();
		Card card1 = hand.bigCard();
		return card.compareDDzTo(card1); // 比较各自最大的牌
	}

	/**
	 * 对card排序
	 */
	public static void sortCards(Vector<Card> aVec) {
		int k;
		Card a, b;

		// 排序算法
		for (int i = 0; i < aVec.size() - 1; i++) {
			k = i;
			for (int j = i + 1; j < aVec.size(); j++) {
				a = aVec.get(k);
				b = aVec.get(j);
				if (a.compareDDzTo(b) > 0)
					k = j;
			}
			if (k != i) {
				a = aVec.get(i);
				b = aVec.get(k);
				aVec.setElementAt(b, i);
				aVec.setElementAt(a, k);
			}
		}
	}

	public Card bigCard() {
		return bigcard;
	}

	public Card smallCard() {
		return smallCard;
	}

	public boolean isPass() {
		return cards == null || cards.isEmpty();
	}

	public boolean isBomb() {
		return value == BOMB || value == HUOJIAN;
	}

	public static void main(String[] args) {
		String cardsStr = "4-0";
		Vector<Card> cards = QzUtils.testCard(cardsStr);
		String cardsStr2 = "1-15";
		Vector<Card> cards2 = QzUtils.testCard(cardsStr2);
		// DdzHand hand = new DdzHand(cards);
		// DdzHand hand2 = new DdzHand(cards2);
		// System.err.println(hand.compareTo(hand2));
		// System.err.println(hand.value);
	}
}
